﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JobShop
{
    //ft06 ft10 ft20 la1 la2 la3 la4 la5 la6 la7 la8 la9 la10 la11 la12 la13 la14 la15 la16 la17 la18 la19 la20 la21 la22 la23 la24 la25 la26 la27 la28 la29 la30 la31 la32 la33 la34 la35 la36 la37 la38 la39 la40 swv01 swv02 swv03 swv04 swv05 swv06 swv07 swv08 swv09 swv10
//la20 la21 la22 la24 la25 la27 la28 la29 la36 la37 la38 la39 la40

#include "stdafx.h"
#include <stdio.h>
#include <fstream.h>
#include <iomanip.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <memory.h>
#include <math.h>
#include <limits.h>
#include <direct.h>

#include <engine.h>
#pragma comment (lib,"libmx.lib")
#pragma comment (lib,"libmex.lib")
#pragma comment (lib,"libeng.lib")

bool ASC=true,DESC=false;
bool ON=true, OFF=false;
bool TFLAG;
int _ITER,IT=50,spIndiv=0;
int totalDuplicates;
double convPattM;
int convPattI;
bool hFlag=false;
char probName[5];
ofstream spcase;
const int maxScen=4;
const char scenID[maxScen][4]={"MBD","ABC","DEF","IYL"};

struct SHIFT
{
	int mID;
	int jID;
	int pos;
	int sTime;
	int eTime;
}*QUEUE,CUR;

typedef struct indivStruct
{
	int indivID;
	int **jobSequences;
	int **machineOrder;
	int *chromosome;
	int **schedule;
	double fitnessValue;
	bool operated;
}individual;

typedef struct UniqueStruct
{
	double fitness;
	int start;
	int count;
}UNQ;
ofstream res;

typedef struct machineBreakdown
{
	char scenCode[4];
	int machine;
	int startTime;
	int endTime;
}MBD;

class JSSP
{
public:
	int totalIteration,totalPopulation;
	int totalJobs,totalMachines;
	int phenotypeSize,chromosomeSize,totalSeeds;
	double cumulativeFitness,avgFitness;
	individual *population,*newPop,bestIndiv,worstIndiv;
	int **machineSequences,**timeSequences,**jobOrder,**priorMatrix,**minStartTime;
	bool **operationFlag;
	int *jobBusy,*machineBusy,*jobFront,*machineFront,*hashTable;
	individual *TL1,*TL2;
	int *TLPresence,TLSIZE,TLFRONT,TLREAR;
	unsigned int *seed,indivSize;
	ofstream fout,fschedule,fresult;
	ifstream fin;
	Engine* mEngine;

// MACHINE BREAKDOWN
	int brokenM,brkStartTime,brkEndTime;
	int totalMBreak;

	JSSP(void){}
	~JSSP(){}
	void initialize(void);
	void loadSeeds(void);
	void randomize(int rnd);
	void memoryAllocation(void);
	void memoryDeAllocation(void);
	void jobInputs(void);
	void createIndividual(individual *I);
	void killIndividual(individual *I);
	void copyIndividual(individual *I1,individual *I2);
	void swapIndividual(individual *I1,individual *I2);
	void copyChromosome(individual *I1,individual *I2);
	void copySequence(individual *I1,individual *I2);
	void modifyChromosome(int row,int col,int mID,individual *I);
	void updateChromosome(individual *I,int priority[],int size,int mID);
	void buildChromosome(individual *I);
	void generateIndivByXover(individual *I);
	void generateIndividual(individual *I,int indivID);
	void initialPopulation(void);
	int getMaxDelayedMachine(individual *I);
	int getMaxDelayedJob(individual *I);
	void localHarmonization(individual *I);
	void globalHarmonization(individual *I);
	bool findFeasibleCluster(int jID,int mID,individual *I);
	bool makeFeasibleIndividual(individual *I);
	bool refindFeasibleCluster(int jID,int mID,int oldMFront,int oldMBusy,individual *I);
	bool remakeFeasibleIndividual(int *oldMachineFront,int *oldMachineBusy,int **newSolution,individual *I);
	bool makeDividedFeasibleIndividual(individual *I);
	bool makeWholeGenerationFeasible(void);
	int findJobInChromosome(individual *I,int jID,int mID);
	inline int maxOf(int A,int B);
	inline int minOf(int A,int B);
	void rankingIndividual(bool param);
	bool isConflict(individual *I,int mID,int J1,int J2,int pos[2]);
	void feasibleExchange(double exP);
	void createNewGeneration(double xP,double mP,double cP,int iter);
	void doXover(individual *I1,individual *I2,int i1,int i2);
	void twoPointTournamentXover(individual *I1,individual *I2,int elitPercentage);
	void bitFlipMutation(individual *I,int noOfBits);
	void showChromosome(individual *I);
	void showSchedule(individual *I);
	double getAverageFitness(void);
	void printChromosomeToFile(individual *I);

	void createSpecialIndividual(individual *I,int order[],int indivID);
	void specialCaseHeuristicIndividual(double avg,double std,double *cumProb,int indivID,individual *I);
	bool generateSpecialIndividual(int special);
	void HOhighestPriority(individual *I,int priors);
	void HOfirstOperationFirst(individual *I,int jID);
	void heuristicMutation(double mP,int noOfJobs);
	void initialHeuristicPopulation(int special);
	void phenotypeToGenotype(individual *I);
	int killDuplicates(double kP);
	int killDuplicates(void);

	void tempShow(void);

	void SOTRule(individual *I);
	void LOTRule(individual *I);
	int getShortestOper(individual *I,int mID);
	void simpleLocalSearch(individual *I);
	void gapRecovery(int N);

	void PUSH(individual *I,int mID,int jID,int pos,int &REAR);
	bool findFeasibleGap(individual *I,int mID,int jID);
	bool shiftingGUT(individual *I);
	void matlabSimulation(individual *I);

	inline int getNextM(int mID,int jID);
	inline int getPrevM(int mID,int jID);
	inline int getNextJ(individual *I,int mID,int jID);
	inline int getPrevJ(individual *I,int mID,int jID);

// TABU SEARCH
	void tabuMemoryAllocation(void);
	void tabuMemoryDeAllocation(void);
	bool checkDuplicate(individual *I1,individual *I2);
	bool checkInTL(individual *I);
	void updateTL(void);
	void buildInitialTabu(void);
	bool addInTL(individual *I);
	bool removeFromTL(void);
	void tabuUpdate(int updGen,int maxDel);
	bool tabuSearch(individual *I);
	bool operateTabu(individual *I,int maxTry);

// SHIFTING BOTTLENECK
	void getOrderedMachine(int* mSeq,bool ORD);
	void shiftingBottleneck(individual *I);
	void orderCurrentBottlneckMachine(int bottleneckM,individual *I);
	void buildMinStartTimeMatrix(void);

	void mutationCheck(individual *I);

//	UNCERTAINITY CONSTRAITS
	int getScenarioInput(char *probname);
	int manageScenario(void);
	int handleMachineBreakdown(int brokenM,int startTime,int endTime,individual *I);
};

void JSSP::randomize(int rnd)
{
	unsigned int seed_val=672632;
	//if(rnd==0) seed_val=rand();
	srand(seed_val);
}

void JSSP::initialize(void)
{
//	loadSeeds();
	srand((unsigned int)time(NULL));
//	srand(seed[rand()%totalSeeds]);
	randomize(0);
	phenotypeSize=totalJobs*totalMachines;
	chromosomeSize=totalMachines*totalJobs*(totalJobs-1)/2;
	indivSize=sizeof(int)*(totalJobs*totalMachines*8+chromosomeSize+1)\
		+sizeof(double)+sizeof(bool);
	memoryAllocation();
	jobInputs();
//	buildMinStartTimeMatrix();
}

void JSSP::loadSeeds(void)
{
	ifstream fileSeed("seeds.txt");
	int x;
	fileSeed>>totalSeeds;
	seed=new unsigned int[totalSeeds];
	for(x=0;x<totalSeeds;x++)
		fileSeed>>seed[x];
	fileSeed.close();
}

void JSSP::memoryAllocation(void)
{
	int x;
	population=new individual[totalPopulation];
	newPop=new individual[totalPopulation];
	for(x=0;x<totalPopulation;x++)
	{
		createIndividual(&population[x]);
		createIndividual(&newPop[x]);
	}
	createIndividual(&bestIndiv);
	createIndividual(&worstIndiv);
	machineSequences=new int*[totalJobs];
	timeSequences=new int*[totalJobs];
	jobOrder=new int*[totalJobs];
	priorMatrix=new int*[totalJobs];
	minStartTime=new int*[totalJobs];
	operationFlag=new bool*[totalJobs];
	for(x=0;x<totalJobs;x++)
	{
		machineSequences[x]=new int[totalMachines];
		timeSequences[x]=new int[totalMachines];
		jobOrder[x]=new int[totalMachines];
		priorMatrix[x]=new int[totalJobs+1];
		minStartTime[x]=new int[totalMachines];
		operationFlag[x]=new bool[totalMachines];
	}
	jobBusy=new int[totalJobs];
	machineBusy=new int[totalMachines];
	jobFront=new int[totalJobs];
	machineFront=new int[totalMachines];

	tabuMemoryAllocation();
}

void JSSP::tabuMemoryAllocation(void)
{
	int x;
	hashTable=new int[totalPopulation];
	TLPresence=new int[TLSIZE];
	TL1=new individual[TLSIZE];
	for(x=0;x<TLSIZE;x++)
		createIndividual(&TL1[x]);
}

void JSSP::memoryDeAllocation(void)
{
	int x;
	for(x=0;x<totalJobs;x++)
	{
		delete machineSequences[x];
		delete timeSequences[x];
		delete jobOrder[x];
		delete priorMatrix[x];
		delete minStartTime[x];
		delete operationFlag[x];
	}
	for(x=0;x<totalPopulation;x++)
	{
		killIndividual(&population[x]);
		killIndividual(&newPop[x]);
	}
	delete population;
	delete newPop;
	delete machineSequences;
	delete timeSequences;
	delete jobOrder;
	delete priorMatrix;
	delete minStartTime;
	delete operationFlag;
	delete jobBusy;
	delete machineBusy;
	delete jobFront;
	delete machineFront;
//	delete seed;

	tabuMemoryDeAllocation();
}

void JSSP::tabuMemoryDeAllocation(void)
{
	int x;
	delete hashTable;
	delete TLPresence;
	for(x=0;x<TLSIZE;x++)
		killIndividual(&TL1[x]);
	delete TL1;
}


void JSSP::jobInputs(void)
{
	int x,y;
	for(x=0;x<totalJobs;x++)
		for(y=0;y<totalMachines;y++)
		{
			fin>>machineSequences[x][y]>>timeSequences[x][y];
 			jobOrder[x][machineSequences[x][y]]=y;
		}
}

void JSSP::createIndividual(individual *I)
{
	int x;
	I->jobSequences=new int*[totalMachines];
	I->machineOrder=new int*[totalMachines];
	I->schedule=new int*[totalMachines];
	I->chromosome=new int[chromosomeSize];
	for(x=0;x<totalMachines;x++)
	{
		I->jobSequences[x]=new int[totalJobs];
		I->machineOrder[x]=new int[totalJobs];
		I->schedule[x]=new int[totalJobs*6];
	}
}

void JSSP::killIndividual(individual *I)
{
	int x;
	for(x=0;x<totalMachines;x++)
	{
		delete I->jobSequences[x];
		delete I->machineOrder[x];
		delete I->schedule[x];
	}
	delete I->jobSequences;
	delete I->machineOrder;
	delete I->schedule;
	delete I->chromosome;
}

void JSSP::copyIndividual(individual *I1,individual *I2)
{
	int x,y,z;
	I1->indivID=I2->indivID;
	I1->fitnessValue=I2->fitnessValue;
	I1->operated=I2->operated;
	for(x=0;x<totalMachines;x++)
		for(y=0;y<totalJobs;y++)
		{
			I1->jobSequences[x][y]=I2->jobSequences[x][y];
			I1->machineOrder[x][y]=I2->machineOrder[x][y];
			for(z=0;z<6;z++)
				I1->schedule[x][y*6+z]=I2->schedule[x][y*6+z];
		}
		for(x=0;x<chromosomeSize;x++)
			I1->chromosome[x]=I2->chromosome[x];
}

/*void JSSP::copyIndividual(individual *I1,individual *I2)
{
	int x,y;
	I1->indivID=I2->indivID;
	I1->fitnessValue=I2->fitnessValue;
	I1->operated=I2->operated;
	memcpy(I1->jobSequences,I2->jobSequences,(totalMachines*totalJobs*sizeof(int)));
//	for(x=0;x<totalMachines;x++)
//	{
//		for(y=0;y<totalJobs;y++)
//			res<<I1->jobSequences[x][y]-I2->jobSequences[x][y]<<" ";
//		res<<endl;
//	}
	memcpy(I1->machineOrder,I2->machineOrder,(totalMachines*totalJobs*sizeof(int)));
//	for(int x=0;x<chromosomeSize;x++)
//		I1->chromosome[x]=I2->chromosome[x];
	memcpy(I1->chromosome,I2->chromosome,(chromosomeSize*sizeof(int)));
//	*(I1->chromosome)=*(I2->chromosome);
	memcpy(I1->schedule,I2->schedule,(6*totalMachines*totalJobs*sizeof(int)));
}*/

void JSSP::tempShow(void)
{
}

void JSSP::swapIndividual(individual *I1,individual *I2)
{
	individual swap;
	swap=*(I1);
	*(I1)=*(I2);
	*(I2)=swap;
}

void JSSP::copySequence(individual *I1,individual *I2)
{
	memcpy(I1->jobSequences,I2->jobSequences,totalMachines*totalJobs*sizeof(int));
}

void JSSP::copyChromosome(individual *I1,individual *I2)
{
	memcpy(I1->chromosome,I2->chromosome,chromosomeSize*sizeof(int));
}

void JSSP::modifyChromosome(int row,int col,int mID,individual *I)
{	
	int m,n,index,val=1;

	if(row==col) return;
	if(row>col)
	{
		n=row;
		row=col;
		col=n;
		val=0;
	}
	n=totalJobs-1;
	m=(n-1)-row;
	index=n*(n+1)/2-m*(m+1)/2-(totalJobs-col);
	index=index*totalMachines+jobOrder[row][mID];
	I->chromosome[index]=val;
}

void JSSP::updateChromosome(individual *I,int priority[],int size,int mID)
{
	int x,y;
	for(x=0;x<(size-1);x++)
		for(y=(x+1);y<size;y++)
			modifyChromosome(priority[x],priority[y],mID,I);
}

void JSSP::buildChromosome(individual *I)
{
	int x;
	for(x=0;x<totalMachines;x++)
		updateChromosome(I,I->jobSequences[x],totalJobs,x);
}

void JSSP::generateIndividual(individual *I,int indivID)
{
	int y;
	I->indivID=indivID;
	for(y=0;y<chromosomeSize;y++)
		I->chromosome[y]=rand()%2;
	localHarmonization(I);
}

void JSSP::generateIndivByXover(individual *I)
{
	int y;
	individual I1,I2;
	createIndividual(&I1);
	createIndividual(&I2);
	twoPointTournamentXover(&I1,&I1,10);
	localHarmonization(&I1);
	localHarmonization(&I2);
	if(I1.fitnessValue<I2.fitnessValue)
		copyIndividual(I,&I1);
	else copyIndividual(I,&I2);
	killIndividual(&I1);
	killIndividual(&I2);
}

void JSSP::initialPopulation(void)
{
	int x,special=0;
//	if(generateSpecialIndividual(special)==false)
//		special=0;
	for(x=special;x<totalPopulation;x++)
	{
		hashTable[x]=x;
		generateIndividual(&population[x],x);
	}
}

int JSSP::getMaxDelayedMachine(individual *I)
{
	int m,x,mID,sum,maxDelay=-1;
	for(m=0;m<totalMachines;m++)
	{
		sum=0;
		for(x=0;x<totalJobs;x++)
			sum+=((I->schedule[m][6*x+2]-I->schedule[m][6*x+1])+(I->schedule[m][6*x+5]-I->schedule[m][6*x+4]));
		if(sum>maxDelay)
		{
			maxDelay=sum;
			mID=m;
		}
	}
	return mID;
}

int JSSP::getMaxDelayedJob(individual *I)
{
	return I->jobSequences[getMaxDelayedMachine(I)][totalJobs-1];
}

void JSSP::localHarmonization(individual *I)
{
	int m,x,y,max,maxPos,count;
		for(m=0;m<totalMachines;m++)
	{
		count=0;
		for(x=0;x<totalJobs;x++)
		{
			count=(int)floor((1.0*count)/totalMachines)*totalMachines+jobOrder[x][m];
			priorMatrix[x][x]=-1;
			for(y=x+1;y<totalJobs;y++)
			{
				priorMatrix[x][y]=I->chromosome[count];
				priorMatrix[y][x]=(I->chromosome[count]+1)%2;
				count+=totalMachines;
			}
			max=0;
			for(y=0;y<totalJobs;y++)
				max+=priorMatrix[x][y];
			priorMatrix[x][totalJobs]=max+1;
		}
		for(x=0;x<totalJobs;x++)
		{
			max=-1;
			maxPos=0;
			for(y=0;y<totalJobs;y++)
				if(max<priorMatrix[y][totalJobs])
				{
					max=priorMatrix[y][totalJobs];
					maxPos=y;
				}
			for(y=0;y<totalJobs;y++)
				if((priorMatrix[maxPos][y]==0)&&(priorMatrix[y][totalJobs]>=0))
				{
					priorMatrix[maxPos][y]=1;	
					priorMatrix[y][maxPos]=0;
					modifyChromosome(maxPos,y,m,I);
				}
			priorMatrix[maxPos][totalJobs]=-1;
			I->jobSequences[m][x]=maxPos;
			I->machineOrder[m][maxPos]=x;
		}
	}
	I->operated=true;
}

void JSSP::globalHarmonization(individual *I)
{
	int x,y,count=0,mID,jID,temp,pos;
	int **hPrior=new int*[totalMachines];
	for(x=0;x<totalMachines;x++)
	{
		hPrior[x]=new int[2*totalJobs+1];
		hPrior[x][2*totalJobs]=0;
	}
	for(jID=0;jID<totalJobs;jID++)
		if(jobFront[jID]<totalMachines)
		{
			mID=machineSequences[jID][jobFront[jID]];
			pos=findJobInChromosome(I,jID,mID);
			for(x=0;x<(2*hPrior[mID][2*totalJobs]);x+=2)
				if(hPrior[mID][x+1]>pos)
					break;
			for(y=(2*hPrior[mID][2*totalJobs]-1);y>=x;y-=2)
			{
				hPrior[mID][y+2]=hPrior[mID][y];
				hPrior[mID][y+1]=hPrior[mID][y-1];
			}
			hPrior[mID][x]=jID;
			hPrior[mID][x+1]=pos;
			hPrior[mID][2*totalJobs]++;
		}
	for(mID=0;mID<totalMachines;mID++)
		for(x=0;x<hPrior[mID][2*totalJobs];x++)
			for(y=hPrior[mID][2*x+1];y>(machineFront[mID]+x);y--)
			{
				temp=I->jobSequences[mID][y];
				I->jobSequences[mID][y]=I->jobSequences[mID][y-1];
				I->jobSequences[mID][y-1]=temp;
				I->machineOrder[mID][I->jobSequences[mID][y-1]]--;
				I->machineOrder[mID][I->jobSequences[mID][y]]++;
			}
	for(x=0;x<totalMachines;x++)
		delete hPrior[x];
	delete hPrior;
}

/*bool JSSP::findFeasibleCluster(int jID,int mID,individual *I)			// MODIFIED
{
	int z,s,cluster=0,slot,mBusy=0,startTime,pos;
	for(pos=0;pos<machineFront[mID];pos++)
	{
		cluster=((jobBusy[jID]>mBusy)?(jobBusy[jID]-mBusy):0);
		slot=(I->schedule[mID][pos*6+2]-I->schedule[mID][pos*6+1])-(cluster+timeSequences[jID][jobFront[jID]]);
		if((slot>=0)&&(jobOrder[jID][mID]<jobFront[jID]))
		{
			I->schedule[mID][pos*6+1]=I->schedule[mID][pos*6+2]-slot;
			startTime=I->schedule[mID][pos*6+1]-timeSequences[jID][jobFront[jID]];
			for(z=machineFront[mID];z>pos;z--)
			{
				I->jobSequences[mID][z]=I->jobSequences[mID][z-1];
				I->machineOrder[mID][I->jobSequences[mID][z-1]]=z;
				for(s=0;s<6;s++)
					I->schedule[mID][z*6+s]=I->schedule[mID][(z-1)*6+s];
			}
			goto label_makeschedule;
		}
		mBusy+=(I->schedule[mID][pos*6+5]-I->schedule[mID][pos*6+1]);
	}
	startTime=maxOf(jobBusy[jID],mBusy);
label_makeschedule:
	I->jobSequences[mID][pos]=jID;
	I->machineOrder[mID][jID]=pos;
	I->schedule[mID][pos*6]=-1;
	I->schedule[mID][pos*6+1]=((pos>0)?(I->schedule[mID][(pos-1)*6+5]):0);
	I->schedule[mID][pos*6+2]=startTime;
	I->schedule[mID][pos*6+3]=jID;
	I->schedule[mID][pos*6+4]=I->schedule[mID][pos*6+2];
	I->schedule[mID][pos*6+5]=I->schedule[mID][pos*6+4]+timeSequences[jID][jobFront[jID]];
	machineBusy[mID]=I->schedule[mID][machineFront[mID]*6+5];
	jobBusy[jID]=I->schedule[mID][pos*6+5];
	machineFront[mID]++;
	jobFront[jID]++;
	return true;
}*/

bool JSSP::findFeasibleCluster(int jID,int mID,individual *I)			// ORIGINAL
{
	int z,s,cluster=0,slot,mBusy=0,startTime,pos;
	for(pos=0;pos<machineFront[mID];pos++)
	{
		cluster=((jobBusy[jID]>mBusy)?(jobBusy[jID]-mBusy):0);
		slot=(I->schedule[mID][pos*6+2]-I->schedule[mID][pos*6+1])-(cluster+timeSequences[jID][jobFront[jID]]);
		if(slot>=0)
		{
			I->schedule[mID][pos*6+1]=I->schedule[mID][pos*6+2]-slot;
			startTime=I->schedule[mID][pos*6+1]-timeSequences[jID][jobFront[jID]];
			for(z=machineFront[mID];z>pos;z--)
			{
				I->jobSequences[mID][z]=I->jobSequences[mID][z-1];
				I->machineOrder[mID][I->jobSequences[mID][z-1]]=z;
				for(s=0;s<6;s++)
					I->schedule[mID][z*6+s]=I->schedule[mID][(z-1)*6+s];
			}
			goto label_makeschedule;
		}
		mBusy+=(I->schedule[mID][pos*6+5]-I->schedule[mID][pos*6+1]);
	}
	startTime=maxOf(jobBusy[jID],mBusy);
label_makeschedule:
	I->jobSequences[mID][pos]=jID;
	I->machineOrder[mID][jID]=pos;
	I->schedule[mID][pos*6]=-1;
	I->schedule[mID][pos*6+1]=((pos>0)?(I->schedule[mID][(pos-1)*6+5]):0);
	I->schedule[mID][pos*6+2]=startTime;
	I->schedule[mID][pos*6+3]=jID;
	I->schedule[mID][pos*6+4]=I->schedule[mID][pos*6+2];
	I->schedule[mID][pos*6+5]=I->schedule[mID][pos*6+4]+timeSequences[jID][jobFront[jID]];
	machineBusy[mID]=I->schedule[mID][machineFront[mID]*6+5];
	jobBusy[jID]=I->schedule[mID][pos*6+5];
	machineFront[mID]++;
	jobFront[jID]++;
	return true;
}

bool JSSP::makeFeasibleIndividual(individual *I)
{
	int x,count=0,scheduleTime=0;
	int mStart=rand()%totalMachines,mID,jID,infTry;
	memset(jobBusy,0,sizeof(int)*totalJobs);
	memset(machineBusy,0,sizeof(int)*totalMachines);
	memset(jobFront,0,sizeof(int)*totalJobs);
	memset(machineFront,0,sizeof(int)*totalMachines);
	for(x=0;x<totalMachines;x++)
		memset(operationFlag[x],false,sizeof(bool)*totalMachines);
	while(true)
	{
		try
		{
		infTry=0;
		for(x=0;infTry<totalMachines;x++)
		{
			mID=(mStart+x)%totalMachines;
			if(machineFront[mID]>=totalJobs)
			{
				infTry++;
				continue;
			}
			jID=I->jobSequences[mID][machineFront[mID]];
			if(machineSequences[jID][jobFront[jID]]==mID)
			{
				infTry=0;
				findFeasibleCluster(jID,mID,I);
				operationFlag[jID][jobOrder[jID][mID]]=true;
				scheduleTime=maxOf(scheduleTime,maxOf(jobBusy[jID],machineBusy[mID]));
				count++;
				//mStart=rand()%totalMachines;
				if(count==phenotypeSize)
				{
					buildChromosome(I);
					I->fitnessValue=(double)scheduleTime;
					I->operated=false;
					return true;
				}
			}
			else infTry++;
		}
		globalHarmonization(I);
		mStart=rand()%totalMachines;
		}
		catch(exception ex)
		{
			MessageBox.Show("abc");
			return;
		}
	}
	return false;
}

/* bool JSSP::makeFeasibleIndividual(individual *I)
{
//reschedule:
	int x,count=0,scheduleTime=0;
	int mStart=rand()%totalMachines,mID,jID,infTry;
	bool fCluster;
	memset(jobBusy,0,sizeof(int)*totalJobs);
	memset(machineBusy,0,sizeof(int)*totalMachines);
	memset(jobFront,0,sizeof(int)*totalJobs);
	memset(machineFront,0,sizeof(int)*totalMachines);
	while(true)
	{
		infTry=0;
		for(x=0;infTry<totalMachines;x++)
		{
			mID=(mStart+x)%totalMachines;
			if(machineFront[mID]>=totalJobs)
			{
				infTry++;
				continue;
			}
			jID=I->jobSequences[mID][machineFront[mID]];
			if(machineSequences[jID][jobFront[jID]]==mID)
			{
				infTry=0;
				fCluster=false;
				if(hFlag==false)
					fCluster=findFeasibleCluster(jID,mID,I);
				if(!fCluster)
				{
					I->machineOrder[mID][jID]=machineFront[mID];
					I->schedule[mID][machineFront[mID]*6]=-1;
					I->schedule[mID][machineFront[mID]*6+1]=machineBusy[mID];
					I->schedule[mID][machineFront[mID]*6+2]=machineBusy[mID]+((jobBusy[jID]>machineBusy[mID])?\
						(jobBusy[jID]-machineBusy[mID]):0);
					I->schedule[mID][machineFront[mID]*6+3]=jID;
					I->schedule[mID][machineFront[mID]*6+4]=I->schedule[mID][machineFront[mID]*6+2];
					I->schedule[mID][machineFront[mID]*6+5]=I->schedule[mID][machineFront[mID]*6+4]+\
						timeSequences[jID][jobFront[jID]];
					jobBusy[jID]=timeSequences[jID][jobFront[jID]]+((jobBusy[jID]>machineBusy[mID])?jobBusy[jID]:machineBusy[mID]);
					machineBusy[mID]=jobBusy[jID];
				}
				scheduleTime=((machineBusy[mID]>scheduleTime)?(machineBusy[mID]):(scheduleTime));
				machineFront[mID]++;
				jobFront[jID]++;
				count++;
				if(count==phenotypeSize)
				{
					buildChromosome(I);
					I->fitnessValue=(double)scheduleTime;
					I->operated=false;
					return true;
				}
			}
			else infTry++;
		}
		globalHarmonization(I);
		mStart=rand()%totalMachines;
	}
	return false;
}*/

bool JSSP::refindFeasibleCluster(int jID,int mID,int oldMFront,int oldMBusy,individual *I)			// ORIGINAL
{
	int z,s,cluster=0,slot,mBusy=oldMBusy,startTime,pos;
	bool chkslot;
	if(mID==1 && jID==4)
		jID=jID;
	for(pos=oldMFront;pos<machineFront[mID];pos++)
	{
		cluster=((jobBusy[jID]>mBusy)?(jobBusy[jID]-mBusy):0);
		slot=(I->schedule[mID][pos*6+2]-maxOf(I->schedule[mID][pos*6+1],mBusy))-(cluster+timeSequences[jID][jobFront[jID]]);
		chkslot=(I->schedule[mID][pos*6+2]>=brkEndTime)&&(I->schedule[mID][pos*6+1]<=brkStartTime)&&(mID==brokenM);
		if(slot>=0 && chkslot!=true)
		{
			I->schedule[mID][pos*6+1]=I->schedule[mID][pos*6+2]-slot;
			startTime=I->schedule[mID][pos*6+1]-timeSequences[jID][jobFront[jID]];
			for(z=machineFront[mID];z>pos;z--)
			{
				I->jobSequences[mID][z]=I->jobSequences[mID][z-1];
				I->machineOrder[mID][I->jobSequences[mID][z-1]]=z;
				for(s=0;s<6;s++)
					I->schedule[mID][z*6+s]=I->schedule[mID][(z-1)*6+s];
			}
			goto label_makeschedule;
		}
		mBusy=I->schedule[mID][pos*6+5];
	}
	startTime=maxOf(jobBusy[jID],mBusy);
label_makeschedule:
	I->jobSequences[mID][pos]=jID;
	I->machineOrder[mID][jID]=pos;
	I->schedule[mID][pos*6]=-1;
	I->schedule[mID][pos*6+1]=((pos>0)?(I->schedule[mID][(pos-1)*6+5]):0);
	I->schedule[mID][pos*6+2]=startTime;
	I->schedule[mID][pos*6+3]=jID;
	I->schedule[mID][pos*6+4]=I->schedule[mID][pos*6+2];
	I->schedule[mID][pos*6+5]=I->schedule[mID][pos*6+4]+timeSequences[jID][jobFront[jID]];
	machineBusy[mID]=I->schedule[mID][machineFront[mID]*6+5];
	jobBusy[jID]=I->schedule[mID][pos*6+5];
	machineFront[mID]++;
	jobFront[jID]++;
	return true;
}

bool JSSP::remakeFeasibleIndividual(int *oldMachineFront,int *oldMachineBusy,int **newSolution,individual *I)
{
	if(phenotypeSize<=0) return true;
	int x,m,s,j,count=0,scheduleTime=0;
	int mStart=rand()%totalMachines,mID=rand()%totalMachines,jID,infTry;
	for(x=0;x<totalMachines;x++)
		memset(operationFlag[x],false,sizeof(bool)*totalMachines);
	while(true)
	{
		infTry=0;
		for(x=0;infTry<totalMachines;x++)
		{
			mID=(mID+1)%totalMachines;
			if(machineFront[mID]>=totalJobs)
			{
				infTry++;
				continue;
			}
			jID=I->jobSequences[mID][machineFront[mID]];
			if(machineSequences[jID][jobFront[jID]]==mID)
			{
				infTry=0;
				refindFeasibleCluster(jID,mID,oldMachineFront[mID],oldMachineBusy[mID],I);
				operationFlag[jID][jobOrder[jID][mID]]=true;
				scheduleTime=maxOf(scheduleTime,maxOf(jobBusy[jID],machineBusy[mID]));
				count++;
				mID=rand()%totalMachines;
				if(count==phenotypeSize)
				{
					buildChromosome(I);
					I->fitnessValue=(double)scheduleTime;
					I->operated=false;
					return true;
				}
				infTry++;
			}
		}
		mID=rand()%totalMachines;
	}
	return false;
}

bool JSSP::makeWholeGenerationFeasible(void)
{
	int x;
	for(x=0;x<totalPopulation;x++)
		if(population[x].operated==true)
//			if(shiftingGUT(&population[x])==false)
			if(makeFeasibleIndividual(&population[x])==false)
				return false;
	return true;
}

void JSSP::rankingIndividual(bool param)
{
	int x,y;
	individual tempI;
	if(param==ASC)
	for(x=0;x<totalPopulation-1;x++)
	{
		for(y=1;y<totalPopulation-x;y++)
			if(population[y-1].fitnessValue>population[y].fitnessValue)
			{
				copyChromosome(&population[y-1],&population[y]);
				swapIndividual(&population[y-1],&population[y]);
//				tempI=population[y-1];
//				population[y-1]=population[y];
//				population[y]=tempI;
			}
	}
	else
	for(x=0;x<totalPopulation-1;x++)
	{
		for(y=1;y<totalPopulation-x;y++)
			if(population[y-1].fitnessValue<population[y].fitnessValue)
			{
				swapIndividual(&population[y-1],&population[y]);
//				tempI=population[y-1];
//				population[y-1]=population[y];
//				population[y]=tempI;
			}
	}
}

bool JSSP::isConflict(individual *I,int mID,int J1,int J2,int pos[2])
{
	int nSTime=((I->machineOrder[mID][J1]==(totalJobs-2))?INT_MAX:(I->schedule[mID][(I->machineOrder[mID][J1]+1)*6+4]));
	int pETime=((I->machineOrder[mID][J2]==1)?0:(I->schedule[mID][(I->machineOrder[mID][J2]-1)*6+5])),mp2=-1,mn1=-1;
	if(jobOrder[J1][mID]!=(totalMachines-1))
	{
		mn1=machineSequences[J1][jobOrder[J1][mID]+1];
		nSTime=minOf(nSTime,I->schedule[mID][I->machineOrder[mn1][J1]*6+4]);
	}
	if(jobOrder[J2][mID]!=0)
	{
		mp2=machineSequences[J2][jobOrder[J2][mID]-1];
		pETime=maxOf(pETime,I->schedule[mID][I->machineOrder[mp2][J2]*6+5]);
	}
	if((nSTime-pETime)>=(timeSequences[J1][jobOrder[J1][mID]]+timeSequences[J2][jobOrder[J2][mID]]))
	{
		pos[1]=pETime;
		pos[0]=minOf((pETime+timeSequences[J2][jobOrder[J2][mID]]),(nSTime-timeSequences[J1][jobOrder[J1][mID]]));
		return false;
	}
	return true;
}

void JSSP::feasibleExchange(double exP)
{
	int ord,J1,mID,jID,pos[2];
	int x,popID,totalExchange=(int)ceil(exP*totalPopulation);
	for(x=0;x<totalExchange;x++)
	{
		popID=1+rand()%(totalPopulation-1);
		jID=getMaxDelayedJob(&population[popID]);
		for(ord=0;ord<=(totalMachines-2);ord++)
		{
			mID=machineSequences[jID][ord];
			if(population[popID].machineOrder[mID][jID]!=0)
			{
				J1=population[popID].jobSequences[mID][population[popID].machineOrder[mID][jID]-1];
				if(!isConflict(&population[popID],mID,J1,jID,pos))
				{
 					population[popID].jobSequences[mID][population[popID].machineOrder[mID][jID]-1]=jID;
					population[popID].jobSequences[mID][population[popID].machineOrder[mID][jID]]=J1;
					population[popID].machineOrder[mID][jID]=population[popID].machineOrder[mID][jID]-1;
					population[popID].machineOrder[mID][J1]=population[popID].machineOrder[mID][jID];
					population[popID].operated=true;
					break;
				}
			}
		}
	}
}

void JSSP::createNewGeneration(double xP,double mP,double cP,int iter)
{
	int x,noBits,overlapFlag=0;
	int percent=(int)(((double)iter/totalIteration)*60);
	double oper;
	bool xFlag=false;
	individual *savePop,tempI;
	for(x=1;x<totalPopulation;x++)
	{
//		if(population[x].operated)
//			goto make_clone;
		oper=1.0*(rand()%100)/100;
		if(oper>=0.0&&oper<=xP)
			if(xFlag==true)
			{
				newPop[x].indivID=population[x].indivID;
				hashTable[newPop[x].indivID]=x;
				twoPointTournamentXover(savePop,&newPop[x],40);
				xFlag=false;
				overlapFlag=1;	// individual already exists in that position
			}
			else
			{
				newPop[x].indivID=population[x].indivID;
				hashTable[newPop[x].indivID]=x;
				savePop=&newPop[x];
				xFlag=true;
				overlapFlag=2;	// individual does not exist
			}
		if(oper>=(1-mP)&&oper<=1.0)
		{
			noBits=1+(int)ceil((((population[x].fitnessValue-population[0].fitnessValue)*0.5)/population[x].fitnessValue)*chromosomeSize);
			noBits=((noBits>chromosomeSize/10)?(chromosomeSize/10):noBits);
//			noBits=4;
//			for(int y=0;y<chromosomeSize;y++)
//				res<<population[x].chromosome[y]<<" ";
//			res<<endl;
			if(overlapFlag!=1)	// individual already exists
				copyIndividual(&newPop[x],&population[x]);
			bitFlipMutation(&newPop[x],noBits);
//			mutationCheck(&newPop[x]);
//			for(y=0;y<chromosomeSize;y++)
//				res<<newPop[x].chromosome[y]<<" ";
//			res<<endl;
		}
		else
//make_clone:
			copyIndividual(&newPop[x],&population[x]);
		overlapFlag=0;
	}
	if(xFlag==true)
		copyIndividual(savePop,&population[savePop->indivID]);
	for(x=1;x<totalPopulation;x++)
	{
		tempI=population[x];
		population[x]=newPop[x];
		newPop[x]=tempI;
	}
}

void JSSP::doXover(individual *I1,individual *I2,int i1,int i2)
{
	int lBound=rand()%chromosomeSize;
	int uBound=rand()%chromosomeSize;
	int x,replace;
	if(lBound>uBound)
	{
		replace=lBound;
		lBound=uBound;
		uBound=replace;
	}
	for(x=0;x<chromosomeSize;x++)
		if(x>=lBound && x<=uBound)
		{
			I1->chromosome[x]=population[i2].chromosome[x];
			I2->chromosome[x]=population[i1].chromosome[x];
		}
		else
		{
			I1->chromosome[x]=population[i1].chromosome[x];
			I2->chromosome[x]=population[i2].chromosome[x];
		}
	localHarmonization(I1);
	localHarmonization(I2);
}

void JSSP::twoPointTournamentXover(individual *I1,individual *I2,int elitPercentage)
{
	int x,index[3],lBound,uBound,replace,elit,rest;
	elit=(int)floor(totalPopulation/(100.0/elitPercentage));
	rest=totalPopulation-elit;
	index[0]=rand()%elit;
	index[1]=elit+rand()%rest;
	index[2]=elit+rand()%rest;
	if(population[index[2]].fitnessValue<population[index[1]].fitnessValue)
		index[1]=index[2];
	doXover(I1,I2,index[0],index[1]);	
}

void JSSP::bitFlipMutation(individual *I,int noOfBits)
{
	int x,pos;
	for(x=0;x<noOfBits;x++)
	{
		pos=rand()%chromosomeSize;
		I->chromosome[pos]=(I->chromosome[pos]+1)%2;
	}
	localHarmonization(I);
	I->operated=true;
}

int JSSP::findJobInChromosome(individual *I,int jID,int mID)
{
	int x;
	for(x=0;x<totalJobs;x++)
		if(I->jobSequences[mID][x]==jID)
			return x;
	return -1;
}

inline int JSSP::maxOf(int A,int B)
{
	return ((A>B)?A:B);
}

inline int JSSP::minOf(int A,int B)
{
	return ((A<B)?A:B);
}

void JSSP::showChromosome(individual *I)
{
	int x,y;
	fout<<I->fitnessValue<<endl;
	for(x=0;x<totalMachines;x++)
	{
		for(y=0;y<totalJobs;y++)
			fout<<I->jobSequences[x][y]<<" ";
		fout<<endl;
	}
	fout<<endl;
}

void JSSP::showSchedule(individual *I)
{
	int x,y;
	fschedule<<totalJobs<<" "<<totalMachines<<endl;
	for(x=0;x<totalMachines;x++)
	{
		for(y=0;y<machineFront[x];y++)
			fschedule<<I->schedule[x][y*6]<<" "<<(I->schedule[x][y*6+2]-I->schedule[x][y*6+1])<<\
			" "<<I->schedule[x][y*6+3]<<" "<<(I->schedule[x][y*6+5]-I->schedule[x][y*6+4])<<" ";
		fschedule<<endl;
	}
	fschedule<<I->fitnessValue<<endl;
}

void JSSP::printChromosomeToFile(individual *I)
{
	ofstream ofchromosome;
	ofchromosome.open("OP\\chromosome.txt");
	int x,y;
	for(x=0;x<totalMachines;x++)
	{
		for(y=0;y<totalJobs;y++)
			ofchromosome<<I->jobSequences[x][y]<<" ";
		ofchromosome<<endl;
	}
/*	for(x=0;x<chromosomeSize;x++)
		ofchromosome<<" "<<I->chromosome[x];	*/
	ofchromosome.close();
}

double JSSP::getAverageFitness(void)
{
	int x;
	double total=0.0;
	for(x=0;x<totalPopulation;x++)
		total+=population[x].fitnessValue;
	return (total/totalPopulation);

}

void JSSP::matlabSimulation(individual *I)
{
	char currentDir[_MAX_PATH],filePath[_MAX_PATH];
	int x,y,sizeMS,totalOper=0,count;
	double *tempSchedule;
	for(x=0;x<totalMachines;x++)
		totalOper+=machineFront[x];
	sizeMS=2+totalMachines+4*totalOper;
	tempSchedule=new double[sizeMS];
	tempSchedule[0]=totalJobs;
	tempSchedule[1]=totalMachines;
	count=2;
	for(x=count;x<(totalMachines+count);x++)
		tempSchedule[x]=machineFront[x-count];
	count+=totalMachines;
	for(x=0;x<totalMachines;x++)
		for(y=0;y<machineFront[x];y++)
		{
			tempSchedule[count++]=-1;
			tempSchedule[count++]=I->schedule[x][y*6+2]-I->schedule[x][y*6+1];
			tempSchedule[count++]=I->schedule[x][y*6+3];
			tempSchedule[count++]=I->schedule[x][y*6+5]-I->schedule[x][y*6+4];
		}
	mEngine=engOpen(NULL);
	if(mEngine==NULL)
	{
		cout<<"Can't Open Matlab Engine"<<endl;
		exit(0);
	}
	_getcwd(currentDir,_MAX_PATH);
	sprintf(filePath,"\\Matlab\\%dx%d (I%dP%d)-%d",totalJobs,totalMachines,totalIteration,totalPopulation,I->indivID);
	strcat(currentDir,filePath);
	mxArray *mxStr=mxCreateString(currentDir);
	engPutVariable(mEngine,"IMGPATH",mxStr);
	mxArray *mxArr=mxCreateDoubleMatrix(1,(sizeMS),mxREAL);
	memcpy((void*)mxGetPr(mxArr),(void*)tempSchedule,sizeof(double)*(sizeMS));
	engPutVariable(mEngine,"Z",mxArr);
	engEvalString(mEngine,"pganttChart(Z,IMGPATH);");
	delete tempSchedule;
}

/********************************* UNCERTAINITY CONSTRAINT *******************************/

int JSSP::handleMachineBreakdown(int brokenM,int brkStartTime,int brkEndTime,individual *I)
{
	bool brkDownOccured;
	int m,j,x,jID,firstOper,saveAvailTime;
	int maxRemainOper,mBusyTime;
	int **newSolution=new int*[totalMachines];
	int *oldMachineFront=new int[totalMachines];
	int *oldMachineBusy=new int[totalMachines];
	phenotypeSize=0;
	memset(machineBusy,0,sizeof(int)*totalMachines);
	memset(machineFront,0,sizeof(int)*totalMachines);
	memset(oldMachineFront,0,sizeof(int)*totalMachines);
	memset(oldMachineBusy,0,sizeof(int)*totalMachines);
	memset(jobBusy,0,sizeof(int)*totalJobs);
	memset(jobFront,-1,sizeof(int)*totalJobs);
	for(m=0;m<totalMachines;m++)
	{
		newSolution[m]=new int[totalJobs];
		firstOper=totalJobs;
		brkDownOccured=false;
		for(j=0;j<totalJobs;j++)
		{
			saveAvailTime=oldMachineBusy[m];
			oldMachineBusy[m]+=I->schedule[m][j*6+2] - I->schedule[m][j*6+1];
			jID=I->schedule[m][j*6+3];
			if(oldMachineBusy[m]>=brkStartTime)
			{
				firstOper=j;
				if(m==brokenM) mBusyTime=maxOf(saveAvailTime,brkEndTime);
				else mBusyTime=maxOf(saveAvailTime,brkStartTime);
				brkDownOccured=true;
				goto break_completed;
			}
			oldMachineBusy[m]+=I->schedule[m][j*6+5]-I->schedule[m][j*6+4];			
			if(oldMachineBusy[m]>=brkStartTime)
			{
				if(m==brokenM)
				{
					if(oldMachineBusy[m]==brkStartTime)
						firstOper=j+1;						
					else firstOper=j;
					mBusyTime=brkEndTime;
				}
				else
				{
					firstOper=j+1;
					mBusyTime=maxOf(oldMachineBusy[m],brkStartTime);
				}
				brkDownOccured=true;
			}
break_completed: 
			if(brkDownOccured==true)
			{
				if(firstOper>0)
				{
					jID=I->schedule[m][(firstOper-1)*6+3];
					jobFront[jID]=maxOf(jobFront[jID],jobOrder[jID][m]);
					jobBusy[jID]=maxOf(jobBusy[jID],I->schedule[m][(firstOper-1)*6+5]);
				}
				oldMachineBusy[m]=mBusyTime;
				break;
			}
			jobFront[jID]=maxOf(jobFront[jID],jobOrder[jID][m]);
			jobBusy[jID]=maxOf(jobBusy[jID],I->schedule[m][j*6+5]);
		}	
		for(x=firstOper;x<totalJobs;x++)
			newSolution[m][x-firstOper]=I->jobSequences[m][x];
		oldMachineFront[m]=firstOper;
		machineFront[m]=firstOper;
		machineBusy[m]=oldMachineBusy[m];
		maxRemainOper=(((totalJobs-firstOper)>maxRemainOper)?(totalJobs-firstOper):maxRemainOper);
		phenotypeSize+=(totalJobs-firstOper);
	}
	for(j=0;j<totalJobs;j++)
		jobFront[j]++;
	remakeFeasibleIndividual(oldMachineFront,oldMachineBusy,newSolution,I);
	phenotypeSize=totalJobs*totalMachines;
	for(m=0;m<totalMachines;m++)
		delete newSolution[m];
	delete newSolution;
	delete oldMachineFront;
	delete oldMachineBusy;
	fout.close();
	return 1;
}

/*int JSSP::handleMachineBreakdown(int brokenM,int brkStartTime,int brkEndTime,individual *I)
{
	bool brkDownOccured;
	int m,j,x,jID,firstOper,saveAvailTime;
	int maxRemainOper,mBusyTime;
	int **newSolution=new int*[totalMachines];
	int *oldMachineFront=new int[totalMachines];
	int *oldMachineBusy=new int[totalMachines];
	phenotypeSize=0;
	memset(machineBusy,0,sizeof(int)*totalMachines);
	memset(machineFront,0,sizeof(int)*totalMachines);
	memset(oldMachineFront,0,sizeof(int)*totalMachines);
	memset(oldMachineBusy,0,sizeof(int)*totalMachines);
	memset(jobBusy,0,sizeof(int)*totalJobs);
	memset(jobFront,-1,sizeof(int)*totalJobs);
	for(m=0;m<totalMachines;m++)
	{
		newSolution[m]=new int[totalJobs];
		firstOper=totalJobs;
		brkDownOccured=false;
		for(j=0;j<totalJobs;j++)
		{
			saveAvailTime=oldMachineBusy[m];
			oldMachineBusy[m]+=I->schedule[m][j*6+2] - I->schedule[m][j*6+1];
			jID=I->schedule[m][j*6+3];
			if(jID==4)
				jID=jID;
			if(oldMachineBusy[m]>=brkStartTime)
			{
				firstOper=j;
				if(m==brokenM) mBusyTime=maxOf(saveAvailTime,brkEndTime);
				else mBusyTime=maxOf(saveAvailTime,brkStartTime);
				brkDownOccured=true;
				goto break_completed;
			}
			oldMachineBusy[m]+=I->schedule[m][j*6+5]-I->schedule[m][j*6+4];			
			if(oldMachineBusy[m]>=brkStartTime)
			{
				if(m==brokenM)
				{
					if(oldMachineBusy[m]==brkStartTime)
						firstOper=j+1;						
					else firstOper=j;
					mBusyTime=brkEndTime;
				}
				else
				{
					firstOper=j+1;
					mBusyTime=maxOf(oldMachineBusy[m],brkStartTime);
				}
				brkDownOccured=true;
			}
break_completed: 
			if(brkDownOccured==true)
			{
				if(firstOper>0)
				{
					jID=I->schedule[m][(firstOper-1)*6+3];
					jobFront[jID]=maxOf(jobFront[jID],jobOrder[jID][m]);
					jobBusy[jID]=maxOf(jobBusy[jID],I->schedule[m][(firstOper-1)*6+5]);
				}
				oldMachineBusy[m]=mBusyTime;
				break;
			}
			jobFront[jID]=maxOf(jobFront[jID],jobOrder[jID][m]);
			jobBusy[jID]=maxOf(jobBusy[jID],I->schedule[m][j*6+5]);
		}	
		for(x=firstOper;x<totalJobs;x++)
			newSolution[m][x-firstOper]=I->jobSequences[m][x];
		oldMachineFront[m]=firstOper;
		machineFront[m]=firstOper;
		machineBusy[m]=oldMachineBusy[m];
		maxRemainOper=(((totalJobs-firstOper)>maxRemainOper)?(totalJobs-firstOper):maxRemainOper);
		phenotypeSize+=(totalJobs-firstOper);
	}
	remakeFeasibleIndividual(oldMachineFront,oldMachineBusy,newSolution,I);
	phenotypeSize=totalJobs*totalMachines;
	for(m=0;m<totalMachines;m++)
		delete newSolution[m];
	delete newSolution;
	delete oldMachineFront;
	delete oldMachineBusy;
	fout.close();
	return 1;
}*/

/*int JSSP::handleMachineBreakdown(int brokenM,int brkStartTime,int brkEndTime,individual *I)
{
	int m,j,x,jID,firstOper,saveAvailTime;
	int maxRemainOper;
	int **newSolution=new int*[totalMachines];
	int *oldMachineFront=new int[totalMachines];
	int *oldMachineBusy=new int[totalMachines];
	phenotypeSize=0;
	memset(machineBusy,0,sizeof(int)*totalMachines);
	memset(machineFront,0,sizeof(int)*totalMachines);
	memset(oldMachineFront,0,sizeof(int)*totalMachines);
	memset(oldMachineBusy,0,sizeof(int)*totalMachines);
	memset(jobBusy,0,sizeof(int)*totalJobs);
	memset(jobFront,0,sizeof(int)*totalJobs);
	for(m=0;m<totalMachines;m++)
	{
		newSolution[m]=new int[totalJobs];
		firstOper=totalJobs;
		for(j=0;j<totalJobs;j++)
		{
			saveAvailTime=oldMachineBusy[m];
			oldMachineBusy[m]+=I->schedule[m][j*6+2] - I->schedule[m][j*6+1];
			if(oldMachineBusy[m]>=brkStartTime)
			{
				firstOper=j;
				jID=I->schedule[m][j*6+3];
				if(m==brokenM)
				{
					saveAvailTime=brkEndTime;
					if(j>0)
						if(oldMachineBusy[m]!=brkStartTime)
						{
						
							jID=I->schedule[m][(j-1)*6+3];
							jobFront[jID]--;
							firstOper--;
						}
				}
				oldMachineBusy[m]=maxOf(saveAvailTime,brkStartTime);
				break;	
			}	
			oldMachineBusy[m]+=I->schedule[m][j*6+5]-I->schedule[m][j*6+4];
			jID=I->schedule[m][j*6+3];
		}	
		for(x=firstOper;x<totalJobs;x++)
			newSolution[m][x-firstOper]=I->jobSequences[m][x];
		oldMachineFront[m]=firstOper;
		machineFront[m]=firstOper;
		machineBusy[m]=oldMachineBusy[m];
		maxRemainOper=(((totalJobs-firstOper)>maxRemainOper)?(totalJobs-firstOper):maxRemainOper);
		phenotypeSize+=(totalJobs-firstOper);
	}
	for(m=0;m<totalMachines;m++)
		cout<<machineBusy[m]<<"\t";
	cout<<endl;
	for(j=0;j<totalJobs;j++)
	{
		jobFront[j]++;
		cout<<jobFront[j]<<"\t"<<machineSequences[j][jobFront[j]]<<endl;
	}
//	for(x=0;x<totalMachines;x++)
//		cout<<((oldMachineFront[x]<totalJobs)?(I->jobSequences[x][oldMachineFront[x]]):(-1))<<"\t";
//	cout<<endl;
//	for(m=0;m<totalJobs;m++)
//		cout<<((jobFront[m]<totalMachines)?(machineSequences[m][jobFront[m]]):(-1))<<"\t";
//	cout<<endl;
	remakeFeasibleIndividual(oldMachineFront,oldMachineBusy,newSolution,I);
	phenotypeSize=totalJobs*totalMachines;
	fout.open("MBD-SCEN.txt");
//	for(m=0;m<totalMachines;m++)
//	{
//		for(x=0;x<totalJobs-machineFront[m];x++)
//			fout<<newSolution[m][x]<<"\t";
//		fout<<endl;
//	}
//	for(m=0;m<totalJobs;m++)
//		cout<<jobFront[m]<<"\t";
//	cout<<endl;
//	for(m=0;m<totalMachines;m++)
//		fout<<oldMachineFront[m]<<"&"<<machineFront[m]<<" ";
//	fout<<endl;
		//fout<<jobOrder[1][m]<<"\t";
	for(m=0;m<totalMachines;m++)
		delete newSolution[m];
	delete newSolution;
	delete oldMachineFront;
	delete oldMachineBusy;
	fout.close();
	return 1;
}*/

int JSSP::getScenarioInput(char *probname)
{
	return 1;	
}

int JSSP::manageScenario(void)
{
	int x,y,i,popID,totalScen;
	char **scenCode,scenInput[4],fname[80];
	sprintf(fname,"%s-scen.txt",probName);
	ifstream sceninf(fname);
	sceninf>>totalScen;
	scenCode=new char*[totalScen];
	for(x=0;x<totalScen;x++)
		scenCode[x]=new char[80];
	matlabSimulation(&population[6]);
	for(x=0;x<totalScen;x++)
	{
		sceninf>>scenInput[0]>>scenInput[1]>>scenInput[2];
		scenInput[3]=NULL;
		for(y=0;y<maxScen;y++)
			if(!strcmpi(scenID[y],scenInput))
				break;
		switch(y)
		{
		case 0:
			sceninf>>brokenM>>brkStartTime>>brkEndTime;
			popID=0;
			for(i=0;i<totalPopulation;i++)
			{
				handleMachineBreakdown(brokenM,brkStartTime,brkEndTime,&population[popID]);
				popID++;
			}
			break;
		case 1:
			break;
		default:
			;
		}
	}
	matlabSimulation(&population[6]);
	sceninf.close();
	return 1;
}

int main(int argc, char* argv[])
{
	JSSP SGA;
	double optimal[41]={ -1,666,655,597,590,593,926,890,863,951,958,1222,1039,1150,1292,1207,945,784,848,842,902,1046,
					  927,1032,935,977,1218,1235,1216,1157,1355,1784,1850,1719,1721,1888,1268,1397,1196,1233,1222};
	int x,rnd,tRun=1,iter,run,arg,totalDel=0,probID,stiter=25;
	double xR,mR,sum;
	char Ifname[80],Rfname[80],Cfname[80],Sfname[80],probSER[3],pID[3];
	double td,tDel,tGen,tDup,bestFitness;
	clock_t stime,ftime;
	for(arg=1;arg<argc;arg++)
	{
		strcpy(probName,argv[arg]);
		probID=(int)(argv[arg][strlen(argv[arg])-1]-'0');
		sprintf(probSER,"%c%c%c",argv[arg][0],argv[arg][1],NULL);
		sprintf(Ifname,"%s.txt",argv[arg]);
		SGA.fin.open(Ifname);
		SGA.fin>>SGA.totalJobs>>SGA.totalMachines;
		SGA.totalIteration=100;
		SGA.totalPopulation=10;
		SGA.TLSIZE=(int)floor(SGA.totalPopulation*1.0/5);
		SGA.initialize();
		sprintf(Sfname,"OP\\schedule-%s (I%d-P%d).txt",argv[arg],SGA.totalIteration,SGA.totalPopulation);
//		sprintf(Cfname,"OP\\phenotype-%s (I%d-P%d).txt",argv[arg],SGA.totalIteration,SGA.totalPopulation);
		sprintf(Rfname,"OP\\result-%s.txt",argv[arg],SGA.totalIteration,SGA.totalPopulation);
		SGA.fschedule.open(Sfname);
//		SGA.fout.open(Cfname);
		SGA.fresult.open(Rfname);
		td=0.2;
		sprintf(Rfname,"OP\\of-%s.txt",argv[arg]);
		res.open(Rfname);
		bestFitness=INT_MAX;
		tGen=0;
		tDel=0;
		tDup=0;
		for(run=1;run<=tRun;run++)
		{
			cout<<"Delete "<<td*100<<"% - "<<"Run "<<run<<endl;
			SGA.initialPopulation();
			convPattM=-1;
			convPattI=-1;
			stime=clock();
			TFLAG=OFF;
			for(iter=1;;iter++)
			{
				if(!SGA.makeWholeGenerationFeasible())
					SGA.fout<<"Can't Make Feasible Solution";
				
				SGA.rankingIndividual(ASC);
				SGA.manageScenario();
				if(iter==stiter)
				{
					tDel+=totalDel;
					tDup+=totalDuplicates;
					cout<<"Del ";
				}
				cout<<SGA.population[0].fitnessValue<<endl;
				if(convPattM!=SGA.population[0].fitnessValue)
				{
					convPattM=SGA.population[0].fitnessValue;
					convPattI=iter;
				}
				sum=0;
				for(x=0;x<SGA.totalPopulation;x++)
					sum+=SGA.population[x].fitnessValue;
				sum/=SGA.totalPopulation;
				if((SGA.population[0].fitnessValue<=optimal[probID])&&(!strcmpi(probSER,"la")))
					goto show_res;
				if(iter==SGA.totalIteration)
					break;
				xR=0.5;
				mR=0.05;
				SGA.createNewGeneration(xR,mR,1.0-xR-mR,iter);
			}
show_res:	ftime=clock();
			tGen+=convPattI;
			if(bestFitness>SGA.population[0].fitnessValue)
				bestFitness=SGA.population[0].fitnessValue;
		}
		SGA.fresult<<bestFitness<<"\t"<<(tGen*1.0/tRun)<<"\t"<<((tDup/tRun)/SGA.totalIteration)<<"\t"<<((tDel/tRun)/SGA.totalIteration)<<endl;
		SGA.copyIndividual(&SGA.bestIndiv,&SGA.population[0]);
		SGA.matlabSimulation(&SGA.bestIndiv);
		SGA.manageScenario();
//		SGA.showSchedule(&SGA.bestIndiv);
		SGA.memoryDeAllocation();
		SGA.fschedule.close();
		SGA.fresult.close();
		SGA.fin.close();
	}
	res.close();
	return 1;
}

}
